\section{memmove() и memcpy()}
\label{memmove_and_DF}
\myindex{\CStandardLibrary!memmove()}
\myindex{\CStandardLibrary!memcpy()}

Разница между этими стандартными ф-циями в том, что 
\IT{memcpy()} слепо копирует блок в другое место,
в то время как \IT{memmove()} корректно обрабатывает блоки, хранимые внахлест.
Например, вы хотите оттащить строку на два байта вперед:

% TODO TikZ
\begin{lstlisting}
`|.|.|h|e|l|l|o|...` -> `|h|e|l|l|o|...`
\end{lstlisting}

\IT{memcpy()}, которая копирует 32-битные или 64-битные слова за раз, или даже \ac{SIMD},
здесь очевидно не сработают, потому как нужно использовать ф-цию копирования работающую побайтово.

Теперь даже более сложный пример, вставьте 2 байта впереди строки:

\begin{lstlisting}
`|h|e|l|l|o|...` -> `|.|.|h|e|l|l|o|...`
\end{lstlisting}

Теперь даже ф-ция работающая побайтово не сработает, нужно копировать байты с конца.

\myindex{x86!\Registers!DF}
Это тот редкий случай, когда x86 флаг \TT{DF} нужно выставлять перед инструкцией \INS{REP MOVSB}:
\TT{DF} определяет направление, и теперь мы должны двигаться назад.

Обычная процедура \IT{memmove()} работает примерно так:
1) если источник ниже назначения, копируем вперед;
2) если источник над назначением, копируем назад.

\myindex{uClibc}
Это \IT{memmove()} из uClibc:

\begin{lstlisting}[style=customc]
void *memmove(void *dest, const void *src, size_t n)
{
	int eax, ecx, esi, edi;
	__asm__ __volatile__(
		"	movl	%%eax, %%edi\n"
		"	cmpl	%%esi, %%eax\n"
		"	je	2f\n" /* (optional) src == dest -> NOP */
		"	jb	1f\n" /* src > dest -> simple copy */
		"	leal	-1(%%esi,%%ecx), %%esi\n"
		"	leal	-1(%%eax,%%ecx), %%edi\n"
		"	std\n"
		"1:	rep; movsb\n"
		"	cld\n"
		"2:\n"
		: "=&c" (ecx), "=&S" (esi), "=&a" (eax), "=&D" (edi)
		: "0" (n), "1" (src), "2" (dest)
		: "memory"
	);
	return (void*)eax;
}
\end{lstlisting}

В первом случае, \INS{REP MOVSB} вызывается со сброшенным флагом \TT{DF}.
Во втором, \TT{DF} в начале выставляется, но потом сбрасывается.

Более сложный алгоритм имеет такую часть:

\q{если разница между \IT{источником} и \IT{назначением} больше чем ширина \glslink{word}{слова},
копируем используя слова нежели байты, и используем побитовое копирование для копирования невыровненных частей}.

\myindex{Glibc}
Так происходит в неоптимизированной части на Си в Glibc 2.24.

Учитывая всё это, \IT{memmove()} может работать медленнее, чем \IT{memcpy()}.
Но некоторые люди, включая Линуса Торвальдса, спорят\footnote{\url{https://bugzilla.redhat.com/show_bug.cgi?id=638477\#c132}}
что \IT{memcpy()} должна быть синонимом \IT{memmove()}, а последняя ф-ция должна в начале проверять,
пересекаются ли буферы или нет, и затем вести себя как \IT{memcpy()} или \IT{memmove()}.
Все же, в наше время, проверка на пересекающиеся буферы это очень дешевая операция.

\subsection{Анти-отладочный прием}

Я слышал об анти-отладочном приеме, где всё что вам нужно для падения процесса это выставить \TT{DF}: следующий вызов
\IT{memcpy()} приведет к падению, потому что будет копировать назад.
Но я не могу это проверить: похоже, все процедуры копирования сбрасывают/выставляют \TT{DF}, как им надо.
С другой стороны, \IT{memmove()} из uClibc, код которой я цитировал здесь,
не имеет явного сброса \TT{DF} (он подразумевает, что \TT{DF} всегда сброшен?),
так что он может и упасть.

